home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-27 | 27.2 KB | 617 lines | [TEXT/ROSA] |
- Common Lisp the Language, 2nd Edition
- -------------------------------------------------------------------------------
-
- 24. Errors
-
- Errors may be signaled for a variety of reasons. Many built-in Common Lisp
- functions may signal an error when given incorrect arguments. Other functions,
- described in this chapter, may be called by user programs for the purpose of
- signaling an error.
-
- When an error is signaled, it is handled in an implementation-dependent way. It
- is expected that each implementation of Common Lisp will provide an interactive
- debugger that prints the error message along with suitable contextual
- information such as which function detected the error. The user may interact
- with the debugger to examine or modify the state of the program in various
- ways, including abandoning the current computation (``aborting to top level'')
- and continuing from the error. What ``continuing'' means depends on how the
- error is signaled; the details of this are specified below for each
- error-signaling function.
-
- [old_change_begin]
- An implementation may also choose to provide means (such as the errset special
- form in MacLisp) for a program to trap all errors and prevent the debugger from
- stepping in for certain errors.
-
- -------------------------------------------------------------------------------
- Rationale: Error handling of adequate flexibility and power for all systems
- written in Common Lisp appears to require a complex error classification
- system. Experience with several error-handling systems in such dialects as
- MacLisp and Lisp Machine Lisp indicates that further experimentation is needed
- in this area; it is too early to define a standard error-handling mechanism.
- Therefore Common Lisp provides standard ways to signal errors, but no standard
- ways to handle errors. Of course a complete Lisp system requires error-handling
- mechanisms, but many useful portable programs do not require them. It is
- expected that a future revision of Common Lisp will address the problem of
- portable error-handling mechanisms.
- -------------------------------------------------------------------------------
-
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This was the result of the research and experimentation
- alluded to in the preceding paragraph. Conditions subsume and generalize the
- notion of errors. The condition system also provides means for handling
- conditions (of which errors are a special case) and for restarting a
- computation after a condition has been signaled. See chapter 29.
- [change_end]
-
- -------------------------------------------------------------------------------
- Compatibility note: What is here called ``continuing,'' Lisp Machine Lisp calls
- ``proceeding'' from an error.
-
- [change_begin]
- In the new terminology introduced in chapter 29, what Lisp Machine Lisp called
- ``proceeding'' would be called ``restarting,'' and ``continuing'' refers to the
- particular restart named continue.
- [change_end]
- -------------------------------------------------------------------------------
-
- -------------------------------------------------------------------------------
-
- * General Error-Signaling Functions
- * Specialized Error-Signaling Forms and Macros
- * Special Forms for Exhaustive Case Analysis
-
- -------------------------------------------------------------------------------
-
- 24.1. General Error-Signaling Functions
-
- The functions in this section provide various mechanisms for signaling
- warnings, breaks, continuable errors, and fatal errors.
-
- In each case, the caller specifies an error message (a string) that may be
- processed (and perhaps displayed to the user) by the error-handling mechanism.
- All messages are constructed by applying the function format to the quantities
- nil, format-string, and all the args to produce a string.
-
- An error message string should not contain a newline character at either the
- beginning or end, and should not contain any sort of herald indicating that it
- is an error. The system will take care of these according to whatever its
- preferred style may be.
-
- Conventionally, error messages are complete English sentences ending with a
- period. Newlines in the middle of long messages are acceptable. There should be
- no indentation after a newline in the middle of an error message. The error
- message need not mention the name of the function that signals the error; it is
- assumed that the debugger will make this information available.
-
- -------------------------------------------------------------------------------
- Implementation note: If the debugger in a particular implementation displays
- error messages indented from the prevailing left margin (for example, indented
- by seven spaces because they are prefixed by the seven-character herald
- ``Error: ''), then the debugger should take care of inserting the appropriate
- indentation into a multi-line error message. Similarly, a debugger that
- prefixes error messages with semicolons so that they appear to be comments
- should take care of inserting a semicolon at the beginning of each line in a
- multi-line error message. These rules are suggested because, even within a
- single implementation, there may be more than one program that presents error
- messages to the user, and they may use different styles of presentation. The
- caller of error cannot anticipate all such possible styles, and so it is
- incumbent upon the presenter of the message to make any necessary adjustments.
- -------------------------------------------------------------------------------
-
- Common Lisp does not specify the manner in which error messages and other
- messages are displayed. For the purposes of exposition, a fairly simple style
- of textual presentation will be used in the examples in this chapter. The
- character > is used to represent the command prompt symbol for a debugger.
-
- [Function]
- error format-string &rest args
-
- [old_change_begin]
- This function signals a fatal error. It is impossible to continue from this
- kind of error; thus error will never return to its caller.
-
- The debugger printout in the following example is typical of what an
- implementation might print when error is called. Suppose that the (misspelled)
- symbol emergnecy-shutdown has no property named command (all too likely, as it
- is probably a typographical error for emergency-shutdown).
-
- (defun command-dispatch (cmd)
- (let ((fn (get cmd 'command)))
- (if (not (null fn))
- (funcall fn))
- (error "The command ~S is unrecognized." cmd))))
-
- (command-dispatch 'emergnecy-shutdown)
- Error: The command EMERGNECY-SHUTDOWN is unrecognized.
- Error signaled by function COMMAND-DISPATCH.
-
-
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of error to
- specify its interaction with the condition system. See section 29.4.1.
- [change_end]
-
- -------------------------------------------------------------------------------
- Compatibility note: Lisp Machine Lisp calls this function ferror. MacLisp has a
- function named error that takes different arguments and can signal either a
- fatal or a continuable error.
- -------------------------------------------------------------------------------
-
- [Function]
- cerror continue-format-string error-format-string &rest args
-
- [old_change_begin]
- cerror is used to signal continuable errors. Like error, it signals an error
- and enters the debugger. However, cerror allows the program to be continued
- from the debugger after resolving the error.
-
- If the program is continued after encountering the error, cerror returns nil.
- The code that follows the call to cerror will then be executed. This code
- should correct the problem, perhaps by accepting a new value from the user if a
- variable was invalid.
-
- If the code that corrects the problem interacts with the program's use and
- might possibly be misled, it should make sure the error has really been
- corrected before continuing. One way to do this is to put the call to cerror
- and the correction code in a loop, checking each time to see if the error has
- been corrected before terminating the loop.
-
- The continue-format-string argument, like the error-format-string argument, is
- given as a control string to format along with the args to construct a message
- string. The error message string is used in the same way that error uses it.
- The continue message string should describe the effect of continuing. The
- intent is that this message can be displayed as an aid to the user in deciding
- whether and how to continue. For example, it might be used by an interactive
- debugger as part of the documentation of its ``continue'' command.
-
- The content of the continue message should adhere to the rules of style for
- error messages. It should not include any statement of how the ``continue''
- command is given, since this may be different for each debugger. (It is up to
- the debugger to supply this information according to its own particular style
- of presentation and user interaction.)
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of cerror to
- specify its interaction with the condition system. See section 29.4.1.
- [change_end]
-
- Here is an example where the caller of cerror, if continued, fixes the problem
- without any further user interaction:
-
- (let ((nvals (list-length vals)))
- (unless (= nvals 3)
- (cond ((< nvals 3)
- (cerror "Assume missing values are zero."
- "Too few values in ~S;~%~
- three are required, ~
- but ~R ~:[were~;was~] supplied."
- nvals (= nvals 1))
- (setq vals (append vals (subseq '(0 0 0) nvals))))
- (t (cerror "Ignore all values after the first three."
- "Too many values in ~S;~%~
- three are required, ~
- but ~R were supplied."
- nvals)
- (setq vals (subseq vals 0 3))))))
-
- If vals were the list (-47), the interaction might look like this:
-
- Error: Too few values in (-47);
- three are required, but one was supplied.
- Error signaled by function EXAMPLE.
- If continued: Assume missing values are zero.
-
-
- In this example, a loop is used to ensure that a test is satisfied. (This
- example could be written more succinctly using assert or check-type, which
- indeed supply such loops.)
-
- (do ()
- ((known-wordp word) word)
- (cerror "You will be prompted for a replacement word."
- "~S is an unknown word (possibly misspelled)."
- word)
- (format *query-io* "~&New word: ")
- (setq word (read *query-io*)))
-
- In complex cases where the error-format-string uses some of the args and the
- continue-format-string uses others, it may be necessary to use the format
- directives ~* and ~@* to skip over unwanted arguments in one or both of the
- format control strings.
-
- -------------------------------------------------------------------------------
- Compatibility note: The Lisp Machine Lisp function fsignal is similar to this,
- but returns :no-action rather than nil, and fails to distinguish between the
- error message and the continue message.
- -------------------------------------------------------------------------------
-
- [Function]
- warn format-string &rest args
-
- [old_change_begin]
- warn prints an error message but normally doesn't go into the debugger.
- (However, this may be controlled by the variable *break-on-warnings*.)
- [old_change_end]
-
- [change_begin]
- X3J13 voted in March 1989 (BREAK-ON-WARNINGS-OBSOLETE) to remove
- *break-on-warnings* from the language. See *break-on-signals*.
- [change_end]
-
- [old_change_begin]
- warn returns nil.
-
- This function would be just the same as format with the output directed to the
- stream in error-output, except that warn may perform various
- implementation-dependent formatting and other actions. For example, an
- implementation of warn should take care of advancing to a fresh line before and
- after the error message and perhaps supplying the name of the function that
- called warn.
- [old_change_end]
-
- -------------------------------------------------------------------------------
- Compatibility note: The Lisp Machine Lisp function compiler:warn is an
- approximate equivalent to this.
- -------------------------------------------------------------------------------
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of warn to specify
- its interaction with the condition system. See section 29.4.9.
- [change_end]
-
- [old_change_begin]
-
- [Variable]
- *break-on-warnings*
-
- If *break-on-warnings* is not nil, then the function warn behaves like break.
- It prints its message and then goes to the debugger or break loop. Continuing
- causes warn to return nil. This flag is intended primarily for use when the
- user is debugging programs that issue warnings; in ``production'' use, the
- value of *break-on-warnings* should be nil.
- [old_change_end]
-
- [change_begin]
- X3J13 voted in March 1989 (BREAK-ON-WARNINGS-OBSOLETE) to remove
- *break-on-warnings* from the language. See *break-on-signals*.
- [change_end]
-
- [Function]
- break &optional format-string &rest args
-
- [old_change_begin]
- break prints the message and goes directly into the debugger, without allowing
- any possibility of interception by programmed error-handling facilities. (Right
- now, there aren't any error-handling facilities defined in Common Lisp, but
- there might be in particular implementations, and there will be some defined by
- Common Lisp in the future.) When continued, break returns nil. It is
- permissible to call break with no arguments; a suitable default message will be
- provided.
-
- break is presumed to be used as a way of inserting temporary debugging
- ``breakpoints'' in a program, not as a way of signaling errors; it is expected
- that continuing from a break will not trigger any unusual recovery action. For
- this reason, break does not take the additional format control string argument
- that cerror takes. This and the lack of any possibility of interception by
- programmed error handling are the only program-visible differences between
- break and cerror. The interactive debugger may choose to display them
- differently; for instance, a cerror message might be prefixed with the herald
- ``Error: '' and a break message with ``Break: ''. This depends on the
- user-interface style of the particular implementation. A particular
- implementation may choose, according to its own style and needs, when break is
- called to go into a debugger different from the one used for handling errors.
- For example, it might go into an ordinary read-eval-print loop identical to the
- top-level one except for the provision of a ``continue'' command that causes
- break to return nil.
- [old_change_end]
-
- -------------------------------------------------------------------------------
- Compatibility note: In MacLisp, break is a special form (FEXPR) that takes two
- optional arguments. The first is a symbol (it would be a string if MacLisp had
- strings), which is not evaluated. The second is evaluated to produce a truth
- value specifying whether break should break (true) or return immediately
- (false). In Common Lisp one makes a call to break conditional by putting it
- inside a conditional form such as when or unless.
- -------------------------------------------------------------------------------
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of break to
- specify its interaction with the condition system. See section 29.4.11.
- [change_end]
-
- -------------------------------------------------------------------------------
-
- 24.2. Specialized Error-Signaling Forms and Macros
-
- These facilities are designed to make it convenient for the user to insert
- error checks into code.
-
- [Macro]
- check-type place typespec [string]
-
- [old_change_begin]
- check-type signals an error if the contents of place are not of the desired
- type. Upon continuing from this error, the user will be asked for a new value;
- check-type will store the new value in place and start over, checking the type
- of the new value and signaling another error if it is still not of the desired
- type. Subforms of place may be evaluated multiple times because of the implicit
- loop generated. check-type returns nil.
-
- The place must be a generalized variable reference acceptable to setf. The
- typespec must be a type specifier; it is not evaluated. The string should be an
- English description of the type, starting with an indefinite article (``a'' or
- ``an''); it is evaluated. If string is not supplied, it is computed
- automatically from typespec. (The optional string argument is allowed because
- some applications of check-type may require a more specific description of what
- is wanted than can be generated automatically from the type specifier.)
-
- The error message will mention place, its contents, and the desired type.
- [old_change_end]
-
- [change_begin]
- The precise format and content of the error message is
- implementation-dependent. The example shown below is representative of current
- practice.
- [change_end]
-
- -------------------------------------------------------------------------------
- Implementation note: An implementation may choose to generate a somewhat
- differently worded error message if it recognizes that place is of a particular
- form, such as one of the arguments to the function that called check-type.
- -------------------------------------------------------------------------------
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of check-type to
- specify its interaction with the condition system. See section 29.4.2.
-
- X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER) to clarify order of
- evaluation (see section 7.2).
- [change_end]
-
- Examples:
-
- (setq aardvarks '(sam harry fred))
- (check-type aardvarks (vector integer))
- Error: The value of AARDVARKS, (SAM HARRY FRED),
- is not a vector of integers.
-
- (setq naards 'foo)
- (check-type naards (integer 0 *) "a positive integer")
- Error: The value of NAARDS, FOO, is not a positive integer.
-
- -------------------------------------------------------------------------------
- Compatibility note: In Lisp Machine Lisp the equivalent facility is called
- check-arg-type.
- -------------------------------------------------------------------------------
-
- [Macro]
- assert test-form [({place}*) [string {arg}*]]
-
- [old_change_begin]
- assert signals an error if the value of test-form is nil. Continuing from this
- error will allow the user to alter the values of some variables, and assert
- will then start over, evaluating test-form again. assert returns nil.
-
- test-form is any form. Each place (there may be any number of them, or none)
- must be a generalized-variable reference acceptable to setf. These should be
- variables on which test-form depends, whose values may sensibly be changed by
- the user in attempting to correct the error. Subforms of each place are only
- evaluated if an error is signaled, and may be re-evaluated if the error is
- re-signaled (after continuing without actually fixing the problem).
-
- The string is an error message string, and the args are additional arguments;
- they are evaluated only if an error is signaled, and re-evaluated if the error
- is signaled again. The function format is applied in the usual way to string
- and args to produce the actual error message. If string is omitted (and
- therefore also the args), a default error message is used.
- [old_change_end]
-
- -------------------------------------------------------------------------------
- Implementation note: The debugger need not include the test-form in the error
- message, and the places should not be included in the message, but they should
- be made available for the user's perusal. If the user gives the ``continue''
- command, he should be presented with the opportunity to alter the values of any
- or all of the references. The details of this depend on the implementation's
- style of user interface, of course.
- -------------------------------------------------------------------------------
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of assert to
- specify its interaction with the condition system. See section 29.4.2.
-
- X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER) to clarify order of
- evaluation (see section 7.2).
-
- X3J13 voted in June 1989 (SETF-MULTIPLE-STORE-VARIABLES) to extend the
- specification of assert to allow a place whose setf method has more than one
- store variable (see define-setf-method).
- [change_end]
-
- Examples:
-
- (assert (valve-closed-p v1))
-
- (assert (valve-closed-p v1) ()
- "Live steam is escaping!")
-
- (assert (valve-closed-p v1)
- ((valve-manual-control v1))
- "Live steam is escaping!")
-
- ;; Note here that the user is invited to change BASE,
- ;; but not the bounds MINBASE and MAXBASE.
-
- (assert (<= minbase base maxbase)
- (base)
- "Base ~D is not in the range ~D, ~D"
- base minbase maxbase)
-
- ;; Note here that it is probably not desirable to include the
- ;; entire contents of the two matrices in the error message.
- ;; It is reasonable to assume that the debugger will give
- ;; the user access to the values of the places A and B.
-
- (assert (= (array-dimension a 1)
- (array-dimension b 0))
- (a b)
- "Cannot multiply a ~D-by-~D matrix ~
- and a ~D-by-~D matrix."
- (array-dimension a 0)
- (array-dimension a 1)
- (array-dimension b 0)
- (array-dimension b 1))
-
- -------------------------------------------------------------------------------
-
- 24.3. Special Forms for Exhaustive Case Analysis
-
- The syntax for etypecase and ctypecase is the same as for typecase, except that
- no otherwise clause is permitted. Similarly, the syntax for ecase and ccase is
- the same as for case except for the otherwise clause.
-
- etypecase and ecase are similar to typecase and case, respectively, but signal
- a non-continuable error rather than returning nil if no clause is selected.
-
- ctypecase and ccase are also similar to typecase and case, but signal a
- continuable error if no clause is selected.
-
- [Macro]
- etypecase keyform {(type {form}*)}*
-
- [old_change_begin]
- This control construct is similar to typecase, but no explicit otherwise or t
- clause is permitted. If no clause is satisfied, etypecase signals an error with
- a message constructed from the clauses. It is not permissible to continue from
- this error. To supply an application-specific error message, the user should
- use typecase with an otherwise clause containing a call to error. The name of
- this function stands for ``exhaustive type case'' or ``error-checking type
- case.'' For example:
-
- (setq x 1/3)
- (etypecase x
- (integer x)
- (symbol (symbol-value x)))
- Error: The value of X, 1/3, is neither
- an integer nor a symbol.
-
-
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of etypecase to
- specify its interaction with the condition system. See section 29.4.3.
- [change_end]
-
- [Macro]
- ctypecase keyplace {(type {form}*)}*
-
- [old_change_begin]
- This control construct is similar to typecase, but no explicit otherwise or t
- clause is permitted. The keyplace must be a generalized variable reference
- acceptable to setf. If no clause is satisfied, ctypecase signals an error with
- a message constructed from the clauses. Continuing from this error causes
- ctypecase to accept a new value from the user, store it into keyplace, and
- start over, making the type tests again. Subforms of keyplace may be evaluated
- multiple times. The name of this function stands for ``continuable exhaustive
- type case.''
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of ctypecase to
- specify its interaction with the condition system. See section 29.4.3.
-
- X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER) to clarify order of
- evaluation (see section 7.2).
- [change_end]
-
- [Macro]
- ecase keyform {({({key}*) | key} {form}*)}*
-
- [old_change_begin]
- This control construct is similar to case, but no explicit otherwise or t
- clause is permitted. If no clause is satisfied, ecase signals an error with a
- message constructed from the clauses. It is not permissible to continue from
- this error. To supply an error message, the user should use case with an
- otherwise clause containing a call to error. The name of this function stands
- for ``exhaustive case'' or ``error-checking case.'' For example:
-
- (setq x 1/3)
- (ecase x
- (alpha (foo))
- (omega (bar))
- ((zeta phi) (baz)))
- Error: The value of X, 1/3, is not
- ALPHA, OMEGA, ZETA, or PHI.
-
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of ecase to
- specify its interaction with the condition system. See section 29.4.3.
- [change_end]
-
- [Macro]
- ccase keyplace {({({key}*) | key} {form}*)}*
-
- [old_change_begin]
- This control construct is similar to case, but no explicit otherwise or t
- clause is permitted. The keyplace must be a generalized variable reference
- acceptable to setf. If no clause is satisfied, ccase signals an error with a
- message constructed from the clauses. Continuing from this error causes ccase
- to accept a new value from the user, store it into keyplace, and start over,
- making the clause tests again. Subforms of keyplace may be evaluated multiple
- times. The name of this function stands for ``continuable exhaustive case.''
- [old_change_end]
-
- [change_begin]
- X3J13 voted in June 1988 (CONDITION-SYSTEM) to adopt a proposal for a Common
- Lisp Condition System. This proposal modifies the definition of ccase to
- specify its interaction with the condition system. See section 29.4.3.
-
- X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER) to clarify order of
- evaluation (see section 7.2).
- [change_end]
-
- -------------------------------------------------------------------------------
- Rationale: The special forms etypecase, ctypecase, ecase, and ccase are
- included in Common Lisp, even though a user could write them himself using the
- other standard facilities provided, because it is likely that many users will
- want these. Common Lisp therefore provides a standard consistent set rather
- than allowing a variety of incompatible dialects to develop.
-
- In addition, experience has shown that some Lisp programmers are too lazy to
- put an appropriate otherwise clause into every case statement to check for
- cases they didn't anticipate, even if they would agree that it will probably
- hurt them later. If an otherwise clause can be included very easily by adding
- one character to the name of the construct, it is perhaps more likely that
- programmers will take the trouble to do it.
-
- The e versions do nothing more than supply automatically generated otherwise
- clauses, but correct implementation of the c versions requires some care. It is
- therefore especially important that the c versions be provided by the system so
- users don't have to puzzle them out on their own. Individual implementations
- may be able to do a better job of supporting these special forms, using their
- own idiosyncratic facilities, than can be done using the error-signaling
- facilities defined by Common Lisp.
- -------------------------------------------------------------------------------
-
- -------------------------------------------------------------------------------
-
-
-